Alicia Lozano Díez y Pablo Ramírez Hereza
7 de marzo de 2022
El objetivo de esta práctica es proporcionar una introducción al procesamiento de señales temporales de voz, y desarrollar de un detector de actividad de voz basado en redes neuronales recurrentes, en particular, LSTM.
CUIDADO: * Los datos proporcionados son de uso exclusivo para esta práctica. No tiene permiso para copiar, distribuir o utilizar el corpus para ningún otro propósito.
Primero vamos a descargar el audio de ejemplo de Moodle (audio_sample.wav) y ejecutar las siguientes líneas de código, que nos permitirán subir el archivo a Google Colab desde el disco local:
from google.colab import files
uploaded = files.upload()
Saving audio_sample.wav to audio_sample.wav
Una vez cargado el fichero de audio, podemos escucharlo de la siguiente manera:
import IPython
wav_file_name = "audio_sample.wav"
print(wav_file_name)
IPython.display.Audio(wav_file_name)
audio_sample.wav
A continuación vamos a definir ciertas funciones para poder hacer manejo de ficheros de audio en Python.
Comenzamos definiendo una función read_recording que leerá un fichero de audio WAV, normalizará la amplitud y devolverá el vector de muestras signal y su frecuencia de muestreo fs.
import scipy.io.wavfile
def read_recording(wav_file_name):
fs, signal = scipy.io.wavfile.read(wav_file_name)
signal = signal/max(abs(signal)) # normalizes amplitude
return fs, signal
Si ejecutamos la función anterior para el fichero de ejemplo, podemos ver la forma en la que se carga dicho fichero de audio en Python. Así, podemos obtener la frecuencia de muestreo y la longitud del fichero en número de muestras:
fs, signal = read_recording(wav_file_name)
print("Signal variable shape: " + str(signal.shape))
print("Sample rate: " + str(fs))
print("File length: " + str(len(signal)) + " samples")
Signal variable shape: (67072,) Sample rate: 16000 File length: 67072 samples
PREGUNTAS:
- ¿Como obtendría la duración de la señal en segundos?
Con la frecuecia de muestreo, cogemos el inverso para ver el tamaño de ventana y lo multiplicamos por el número de muestras.
((1/16000) * 67072)
4.192
Obtenemos 4 segundos
También podemos representar la señal y ver su forma de onda. Para ello, definimos la función plot_signal como sigue:
import matplotlib.pyplot as plt
import numpy as np
def plot_signal(signal, fs, ylabel="", title=""):
dur = len(signal)/fs
step = 1./fs
t_axis = np.arange(0., dur, step)
plt.plot(t_axis, signal)
plt.xlim([0, dur])
plt.ylabel(ylabel)
plt.xlabel('Time (seconds)')
plt.title(title)
plt.grid(True)
Y utilizando la función anterior, obtenemos su representación (amplitud frente al tiempo):
PREGUNTAS: - Incluya en el informe la representación obtenida.
plot_signal(signal, fs, "Amplitude", wav_file_name)
plt.show()
En esta práctica, vamos a desarrollar un detector de actividad de voz, que determinará qué segmentos de la señal de voz son realmente voz y cuáles silencio.
Por ello, vamos a ver dos ejemplos de etiquetas ground truth, que corresponden al fichero de audio de ejemplo.
Primero, descargamos de Moodle las etiquetas de voz/silencio que están en los ficheros audio_sample_labels_1.voz y audio_sample_labels_2.voz y las cargamos en Google Colab como en el caso anterior.
from google.colab import files
uploaded = files.upload()
Saving audio_sample_labels_1.voz to audio_sample_labels_1.voz
Estas etiquetas están guardadas en ficheros de texto y podemos cargarlas en Python de la siguiente manera:
labels_file_name = 'audio_sample_labels_1.voz'
voice_labels = np.loadtxt(labels_file_name)
Con el siguiente código, podemos representar la señal de voz así como sus etiquetas en la misma figura:
plot_signal(signal, fs)
plot_signal(voice_labels*2-1, fs, "Amplitude", wav_file_name)
plt.show()
Las etiquetas de voz/silencio provienen de distintos detectores de actividad de voz.
PREGUNTAS: - ¿Qué valores tienen las etiquetas? ¿Qué significan dichos valores? Las etiquetas corresponden a una señal cuadrada que toma el valor 1 cuando detecta voz y -1 cuando detecta silencio en la señal a etiquetar.
- ¿Por qué se representa _voicelabels*2-1? Porque voice_labels es una señal binaria que toma valores entre 0 y 1, la amplitud de voz de nuestra señal normalizada toma valores entre 1 y -1. Haciendo voicelabels*2-1, lo que hacemos es que los valores de las etiquetas que antes estaban en 1 se mantengan en 1, y los que estaban en 0 se mapeen a -1.
plot_signal(signal, fs)
plot_signal(voice_labels, fs, "Amplitude", wav_file_name)
plt.show()
- Represente la señal de voz junto con las etiquetas para ambos casos e incluya las figuras en el informe de la práctica. ¿Qué diferencias observas? ¿A qué se puede deber?
PARA audio_sample_labels_1.voz:
plot_signal(signal, fs)
plot_signal(voice_labels*2-1, fs, "Amplitude", wav_file_name)
plt.show()
PARA audio_sample_labels_2.voz
from google.colab import files
uploaded = files.upload()
Saving audio_sample_labels_2.voz to audio_sample_labels_2.voz
labels_file_name_2 = 'audio_sample_labels_2.voz'
voice_labels_2 = np.loadtxt(labels_file_name_2)
plot_signal(signal, fs)
plot_signal(voice_labels_2*2-1, fs, "Amplitude", wav_file_name)
plt.show()
Vemos que voice_labels_2, es mucho menos agresiva a la hora de considerar silencios. Cuando hay intervalos con un umbral de amplitud un poco más alto(por ejemplo segundo 1.8), considera dichos intervalos como voz y no como silencio. El umbral de amplitud para considerar una ventana como silencio en este sistema es más bajo que en voice_labels_1. Como resultado, voice_labels_2 hace más suaves los cambios temporales entre voz y no voz.
- ¿Qué cantidad de voz/silencio hay en cada etiquetado?
Consideramos la frecuencia de muestreo de la señal de voz y el tiempo que ocupa cada label "voz" o "silencio" dentro de ella:
print('VOICE_LABELS_1 : Segundos Voz:',np.count_nonzero(voice_labels == 1) , '\t Segundo Silencio:',np.count_nonzero(voice_labels == 0) )
print('VOICE_LABELS_2 : Segundos Voz:',np.count_nonzero(voice_labels_2 == 1) , '\t Segundo Silencio:',np.count_nonzero(voice_labels_2 == 0) )
VOICE_LABELS_1 : Segundos Voz: 51151 Segundo Silencio: 15921 VOICE_LABELS_2 : Segundos Voz: 56871 Segundo Silencio: 10201
En la mayoría de sistemas de reconocimiento de patrones, un primer paso es la extracción de características. Esto consiste, a grandes rasgos, en obtener una representación de los datos de entrada, que serán utilizados para un posterior modelado.
En nuestro caso, vamos pasar de la señal en crudo "raw" dada por las muestras (signal), a una secuencia de vectores de características que extraigan información a corto plazo de la misma y la representen. Esta sería la entrada a nuestro sistema de detección de voz basado en redes neuronales.
Para ver algunos ejemplos, vamos a utilizar la librería librosa (https://librosa.org/doc/latest/index.html).
Dentro de esta librería, tenemos funciones para extraer distintos tipos de características de la señal de voz, como por ejemplo el espectrograma en escala Mel (melspectrogram).
Estas características a corto plazo, se extraen en ventanas de unos pocos milisegundos con o sin solapamiento.
Un ejemplo sería el siguiente:
import librosa
mel_spec = librosa.feature.melspectrogram(signal,fs,n_mels=23,win_length=320,hop_length=160)
print(mel_spec.shape)
print(signal.shape)
(23, 420) (67072,)
PREGUNTAS:
- ¿Qué se obtiene de la función anterior?
El array con el espectrograma Mel.
- ¿Qué significan los valores de los parámetros _winlength y _hoplength?
win_len:tamaño de la ventana, es decir, el número de muestas que cogemos en cada frame
hop_len: El desplazamiento que cojo dentro del tamaño de ventana sobre el que empiezo a solapar las ventanas cogidas de las muestras. En nuestro caso tenemos un win_length=320 y un hop_length=160, con lo que estamos solapando sobre la mitad cada ventana.
- ¿Qué dimensiones de _melspec obtienes? ¿Qué significan? Obtenemos un shape de(23, 420), es decir, 23 vectores de características de tamaño 420.
De esta manera, podríamos obtener una parametrización de las señales para ser utilizadas como entrada a nuestra red neuronal.
Para los siguientes apartados, se proporcionan los vectores de características MFCC para una serie de audios que se utilizarán como conjunto de entrenamiento del modelo de VAD.
Primero vamos a descargar la lista de identificadores de los datos de entrenamiento de la práctica.
Para ello, necesitaremos descargar de Moodle el fichero training_VAD.lst, y ejecutar las siguientes líneas de código, que nos permitirán cargar el archivo a Google Colab desde el disco local:
from google.colab import files
uploaded = files.upload()
Saving training_VAD.lst to training_VAD.lst
A continuación cargamos los identificadores contenidos en el fichero en una lista en Python:
file_train_list = 'training_VAD.lst' # mat files containing data + labels
f = open(file_train_list, 'r')
train_list = f.read().splitlines()
f.close()
Podemos ver algunos de ellos (los primeros 10 identificatores) de la siguiente forma:
print(train_list[:10])
['features_labs_1.mat', 'features_labs_10.mat', 'features_labs_100.mat', 'features_labs_101.mat', 'features_labs_102.mat', 'features_labs_103.mat', 'features_labs_104.mat', 'features_labs_105.mat', 'features_labs_106.mat', 'features_labs_107.mat']
Ahora, descargaremos de Moodle el fichero data_download_onedrive_training_VAD.sh, y ejecutaremos las siguientes líneas de código, que nos permitirán cargar el archivo a Google Colab desde el disco local:
from google.colab import files
uploaded = files.upload()
Saving data_download_onedrive_training_VAD.sh to data_download_onedrive_training_VAD.sh
Para descargar el conjunto de datos desde One drive, ejecutamos el script cargado anteriormente de la siguiente manera:
!chmod 755 data_download_onedrive_training_VAD.sh
!./data_download_onedrive_training_VAD.sh
--2022-03-14 04:52:27-- https://dauam-my.sharepoint.com/:u:/g/personal/alicia_lozano_uam_es/EdCueYU7BpNAuo6BawH8hJAB5rclap745BmsPzXgSPhsgw?download=1 Resolving dauam-my.sharepoint.com (dauam-my.sharepoint.com)... 13.107.136.9, 13.107.138.9 Connecting to dauam-my.sharepoint.com (dauam-my.sharepoint.com)|13.107.136.9|:443... connected. HTTP request sent, awaiting response... 302 Found Location: /personal/alicia_lozano_uam_es/Documents/PIT/training_VAD.zip [following] --2022-03-14 04:52:28-- https://dauam-my.sharepoint.com/personal/alicia_lozano_uam_es/Documents/PIT/training_VAD.zip Reusing existing connection to dauam-my.sharepoint.com:443. HTTP request sent, awaiting response... 200 OK Length: 3638232935 (3.4G) [application/x-zip-compressed] Saving to: ‘EdCueYU7BpNAuo6BawH8hJAB5rclap745BmsPzXgSPhsgw?download=1’ EdCueYU7BpNAuo6BawH 100%[===================>] 3.39G 59.6MB/s in 70s 2022-03-14 04:53:39 (49.3 MB/s) - ‘EdCueYU7BpNAuo6BawH8hJAB5rclap745BmsPzXgSPhsgw?download=1’ saved [3638232935/3638232935]
Este script descargará los datos de One Drive y los cargará en Google Colab, descomprimiéndolos en la carpeta data/training_VAD.
Podemos comprobar que los ficheros .mat se encuentran en el directorio esperado:
!ls data/training_VAD/ | head
features_labs_100.mat features_labs_101.mat features_labs_102.mat features_labs_103.mat features_labs_104.mat features_labs_105.mat features_labs_106.mat features_labs_107.mat features_labs_108.mat features_labs_109.mat
Utilizando la librería Pytorch (https://pytorch.org/docs/stable/index.html), vamos a definir un modelo de ejemplo con una capa LSTM y una capa de salida. La capa de salida estará formada por una única neurona. La salida indicará la probabilidad de voz/silencio utilizando una función sigmoid.
import torch
import torch.nn as nn
import torch.nn.functional as F
class Model_1(nn.Module):
def __init__(self, feat_dim=20):
super(Model_1, self).__init__()
self.lstm = nn.LSTM(feat_dim,256,batch_first=True,bidirectional=False)
self.output = nn.Linear(256,1)
def forward(self, x):
out = self.lstm(x)[0]
out = torch.sigmoid(out)
return out.squeeze(-1)
PREGUNTAS: - ¿Qué tamaño tiene la entrada a la capa LSTM? El tamaño del vector de características, feat_dim.
- ¿Cuántas unidades (celdas) tiene dicha capa LSTM? 256
- ¿Qué tipo de matriz espera la LSTM? Mirar la documentación y describir brevemente.
Los datos de entrada son tensores(matrices). Espera dos entradas, concretamente input y (h_0, c_0).
Con input: es un tensor con las características de entrada de la secuencia. Tiene dimensiones tensor of shape (Longitud secuencia ,Tamaño de la entrada) para una entrada unbatched, (Longitud secuencia , Tamaño del Batch, Tamaño de la entrada) cuando batch_first=False, y ( Tamaño del Batch, Longitud secuencia , Tamaño de la entrada) cuando cuando batch_first=True.
h_0: Tensor con los estados iniciales ocultos para cada elemento en el batch. Por defecto ceros si no se le pasa como argumento.
c_0: Tensor con los estados iniciales de cada celda para cada elemento en el batch.Por defecto ceros si no se le pasa como argumento.
- Revisar la documentación de torch.nn.LSTM y describir brevemente los argumentos _batchfirst, bidirectional y dropout.
batch_first: Si está a True, los tensores de entrada y salida son proporcionados como (batch, seq, feature) en vez de (seq, batch, feature). Por defecto está a False. Es decir, cambia el orden de llamada.
bidirectional: Si está a True, la LTSM se convierte en bidireccional.
dropout: Si no es cero, se añade una capa de dropout en las salidas de cada capa LSTM exceptuando la última, con valor de probabilidad el valor pasado como dropout. Es decir, ignorar a veces algunas celdas para evitar la dependencia total de la red sobre ellas.
- En este modelo, estamos utilizando una única neurona a la salida. ¿Hay alguna otra alternativa? ¿Se seguiría utilizando una función sigmoid?
Sí, podríamos utiliar una función softmax, con dos neuronas de salida, donde cada neurona representa la probabilidad de que la salida sea voz o silencio.
- ¿Para qué sirve la función forward definida en la clase _Model1? Sirve para conectar la arquitectura de la red que hemos creado, la LSTM con la salida(sigmoide) para definir nuestro modelo, proporcionando la salida en el formato deseado.
Una vez definida la clase, podemos crear nuestra instancia del modelo y cargarlo en la GPU con el siguiente código:
model = Model_2(feat_dim=20)
model = model.to(torch.device("cuda"))
print(model)
Model_1( (lstm): LSTM(20, 256, batch_first=True) (output): Linear(in_features=256, out_features=1, bias=True) )
Nuestra variable model contiene el modelo, y ya estamos listos para entrenarlo y evaluarlo.
Como hemos visto anteriormente, nuestros datos están guardados en ficheros de Matlab (.mat). Cada uno de estos ficheros contiene una matriz X correspondiente a las secuencias de características MFCC (con sus derivadas de primer y segundo orden), y un vector Y con las etiquetas de voz/silencio correspondientes.
Veamos un ejemplo:
features_file = 'data/training_VAD/features_labs_1.mat'
import scipy.io
features = scipy.io.loadmat(features_file)['X']
labels = scipy.io.loadmat(features_file)['Y']
print(features.shape)
print(labels.shape)
(46654, 60) (46654, 1)
PREGUNTAS: Elegir un fichero de entrenamiento y responder a las siguientes preguntas:
Features (46654, 60) Y labels(46654, 1).
Con el número de ventanas o frames tomados.
El entrenamiento del modelo se va a realizar mediante descenso por gradiente (o alguna de sus variantes) basado en batches.
Para preparar cada uno de estos batches que servirán de entrada a nuestro modelo LSTM, debemos almacenar las características en secuencias de la misma longitud. El siguiente código lee las características (get_fea) y sus correspondientes etiquetas (get_lab) de un fragmento aleatorio del fichero de entrada.
import scipy.io
import numpy as np
def get_fea(segment, rand_idx):
data = scipy.io.loadmat(segment)['X']
if data.shape[0] <= length_segments:
start_frame = 0
else:
start_frame = np.random.permutation(data.shape[0]-length_segments)[0]
end_frame = np.min((start_frame + length_segments,data.shape[0]))
rand_idx[segment] = start_frame
feat = data[start_frame:end_frame,:20] # discard D and DD, just 20 MFCCs
return feat[np.newaxis, :, :]
def get_lab(segment, rand_idx):
data = scipy.io.loadmat(segment)['Y']
start_frame = rand_idx[segment]
end_frame = np.min((start_frame + length_segments, data.shape[0]))
labs = data[start_frame:end_frame].flatten()
return labs[np.newaxis,:]
PREGUNTAS: Analizar las funciones anteriores detenidamente y responder a las siguientes cuestiones:
¿De qué tamaño son los fragmentos que se están leyendo?
De logitud length_segments
¿Para qué sirve _randidx?
Sirve para cuadrar las etiquetas con información de la señal.
Una vez definidas las funciones de lectura de datos y preparación del formato que necesitamos para la entrada a la red LSTM, podemos utilizar el siguiente código para entrenarlo.
length_segments = 300
path_in_feat = 'data/training_VAD/'
from torch import optim
criterion = nn.BCELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
batch_size = 51
segment_sets = np.array_split(train_list, len(train_list)/batch_size)
max_iters = 5
for epoch in range(1, max_iters):
print('Epoch: ',epoch)
model.train()
cache_loss = 0
y_real = []
y_predicted = []
for ii, segment_set in enumerate(segment_sets):
rand_idx = {}
optimizer.zero_grad()
# Create training batches
train_batch = np.vstack([get_fea(path_in_feat + segment, rand_idx) for segment in segment_set])
labs_batch = np.vstack([get_lab(path_in_feat + segment, rand_idx).astype(np.int16) for segment in segment_set])
assert len(labs_batch) == len(train_batch) # make sure that all frames have defined label
# Shuffle the data and place them into Pytorch tensors
shuffle = np.random.permutation(len(labs_batch))
labs_batch = torch.tensor(labs_batch.take(shuffle, axis=0).astype("float32")).to(torch.device("cuda"))
train_batch = torch.tensor(train_batch.take(shuffle, axis=0).astype("float32")).to(torch.device("cuda"))
# Forward the data through the network
outputs = model(train_batch)
predictions = outputs.cpu().detach().numpy().flatten()
y_predicted.extend([1 if i>= 0.5 else 0 for i in predictions])
y_real.extend(labs_batch.cpu().numpy().flatten() )
# Compute cost
loss = criterion(outputs, labs_batch)
# Backward step
loss.backward()
optimizer.step()
cache_loss += loss.item()
print("Loss: " + str(cache_loss/len(train_batch)))
y_predicted = np.array(y_predicted, dtype= np.float32)
y_real = np.array(y_real, dtype= np.float32)
acc = np.mean(y_real == y_predicted)
print("Accuracy: " + str(acc))
Epoch: 1 Loss: 0.07802955952345156 Accuracy: 0.8263986928104575 Epoch: 2 Loss: 0.06419467984461318 Accuracy: 0.8666470588235294 Epoch: 3 Loss: 0.06161036970568638 Accuracy: 0.8762745098039215 Epoch: 4 Loss: 0.053463984938228834 Accuracy: 0.8950980392156863
PREGUNTAS: Analizar el código anterior cuidadosamente y ejecutarlo. A continuación, responder a las siguientes cuestiones:
- ¿Qué función de coste se está optimizando? Describir brevemente con ayuda de la documentación. Se utiliza BCELoss, que mide la entropía cruzada binaria( Binary Cross Entropy) entre el objetivo y las probabilidades de entrada tal que:
$$l_{n} = -w_{n}[y_{n}logx_{n} + (1-y_{n})log(1-x_{n})]$$Siendo x cada batch. Después se hace la metdia de $l_{n}$ para cada batch(o la suma si reduction=None)
- ¿Qué optimizador se ha definido?
El optimizador Adam con una tasa de aprendizaje de lr=0.001. Es un algoritmo para la optimización basada en el gradiente de primer orden de funciones objetivo estocásticas, basado en estimaciones adaptativas de momentos de orden inferior.
- ¿Para qué se utiliza _batchsize?
Para decirle al cargador de datos cuantos datos de entrada tiene que coger por lotes para pasarselos a la red en cada iteración en vez de hacerlo de uno en uno.
- Describir brevemente la creación de los batches.
Cogemos indices aleatorios para coger filas de los datos de entrenamiento(para las etiquetas en concordancia a los features de entrenamiento, esto mediante las funciones get_fea() y get_lab() ). Los apilamos en arrays numpy verticalmente con np.vstack. Los permutamos y los almacenamos en formato de tensor.
Este proceso se repite para cada época.
- ¿Qué línea de código realiza el forward pass?
outputs = model(train_batch)
- ¿Qué línea de código realiza el backward pass?
loss.backward() Que calcula los deltas(errores) mediante backpropagation, de ahí que llame al objeto de loss. Luego
optimizer.step() El optimizador actualiza los pesos con los gradientes que ha calculado.
- ¿Cuántas iteraciones del algoritmo ha realizado? ¿Qué observa en la evolución de la función de coste?
4 épocas, que su valor va disminuyendo en cada iteración, acercándose cada vez más a 0.
- Añada al código el cálculo de la precisión o accuracy, de tal manera que se muestre por pantalla dicho valor en cada iteración (similar a lo que ocurre con el valor del coste loss). Copiar el código en el informe y describir brevemente.
El codigo se incorpora en el código de arriba. Calculamos el accuracy contando el número de veces que nuestro podemos acierta dividido entre el numero total de casos a comprobar. Es decir, para cada predicción vemos si el resultado predicho es el del label. Cabe tener en cuenta que la salida de la red es una probabilidad, por ello si es mayor o igual de 0.5 se considera clase 1, si no clase 0.
- ¿Qué valor de coste y accuracy obtiene? ¿Cómo se puede mejorar?
Para la última época un valos de perdida de 0.053 y un Accuracy de 0.895.
Se podría mejorar empleando más épocas en el entranamiento y utilizando si estuvieran disponibles un conjunto de datos de entrenamiento mayor.
Una vez entrenado el modelo, vamos a evaluarlo en un ejemplo en concreto.
Descargue de Moodle el fichero audio_sample_test.wav, con sus correspondientes características y etiquetas audio_sample_test.mat y evalúe el rendimiento en el mismo.
PREGUNTAS:
#Carga del fichero audio_sample_test.mat
from google.colab import files
uploaded = files.upload()
Saving audio_sample_test.mat to audio_sample_test.mat
features_file = 'audio_sample_test.mat'
features_test = scipy.io.loadmat(features_file)['X'][:,:20]
labels_test = scipy.io.loadmat(features_file)['Y']
test_batch = features_test[np.newaxis,:,:]
test_batch = torch.tensor(test_batch.astype("float32")).to(torch.device("cuda"))
model.eval()
# Disable grad
with torch.no_grad():
output_2 = model(test_batch)
output_2 = output_2.cpu().numpy()[0]
test_predictions = np.array(output_2, dtype= np.float32).flatten()
y_predicted_test = np.array([1 if i>= 0.5 else 0 for i in test_predictions])
y_real_test = labels_test.flatten()
y_real_test = np.array(y_real, dtype= np.float32)
acc = np.mean(y_real == y_predicted_test)
print("Test Accuracy: " + str(acc))
Test Accuracy: 0.9072987520985859
Un accuracy del 90,73%
#carga de audio_sample_test.wav
from google.colab import files
uploaded = files.upload()
Saving audio_sample_test.wav to audio_sample_test.wav
wav_file_name = "audio_sample_test.wav"
fs_test, signal_test = read_recording(wav_file_name)
print("Signal variable shape: " + str(signal_test.shape))
print("Sample rate: " + str(fs_test))
print("File length: " + str(len(signal_test)) + " samples")
Signal variable shape: (4800160,) Sample rate: 8000 File length: 4800160 samples
ETIQUETAS GROUND TRUTH:
#Queremos coger solo 10s de audio
frame_size = 1/fs_test
#Calculamos el numero de ventanas necesarias para 10s de señal
n_ventanas =int(10/frame_size)
signal_test =signal_test[0:n_ventanas]
plot_signal(signal_test[0:n_ventanas], fs_test, "Amplitude", wav_file_name)
#Labels: OJO: Están tomadas cada 10ms y no cada 20ms
labels_range = [0.01 * (i+1) for i in range(1000)]
a = labels_test.flatten()[0:1000]
a = np.array(a, dtype= np.float32)
a = a*2-1
plt.plot(labels_range,a)
plt.show()
ETIQUETAS PREDICHAS POR NUESTRO MODELO:
#Queremos coger solo 10s de audio
frame_size = 1/fs_test
#Calculamos el numero de ventanas necesarias para 10s de señal
n_ventanas =int(10/frame_size)
signal_test =signal_test[0:n_ventanas]
plot_signal(signal_test[0:n_ventanas], fs_test, "Amplitude", wav_file_name)
#Labels: OJO: Están tomadas cada 10ms y no cada 20ms
labels_range = [0.01 * (i+1) for i in range(1000)]
b = y_predicted_test[0:1000]
b = np.array(a, dtype= np.float32)
plt.plot(labels_range,b)
plt.show()
Podemos afirmar que visualmente nuestro modelo es bueno
wav_file_name = "audio_sample_test.wav"
print(wav_file_name)
IPython.display.Audio(wav_file_name)
audio_sample_test.wav